/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package sd_proj1.monSolution;

import java.util.TreeMap;
import sd_proj1.interfaces.*;

/**
 *
 * @author Pedro Costa Correia - 32795
 * @author Valter Pedro Lopes Vicente - 39360
 */
public class GeneralState implements ICraftsmanFifo, ICustomerFifo, IOwnerFifo {

	/**
	 *  Instanciação da fila de pedidos.
	 *
	 *    @serialField fifo
	 */
	private MemFIFO fifo = new MemFIFO(1000);
	/**
	 *  Quantidade de pedidos que a dona tem para tratar.
	 *
	 *    @serialField nOwnerReqs
	 */
	private int nOwnerReqs = 0;
	/**
	 *  Quantidade de produtos que são necessários a dona transportar da oficina para a loja.
	 *
	 *    @serialField nProductsTransport
	 */
	private int nProductsTransport = 0;
	/**
	 *  Parâmetro booleano que define se os artesãos estão todos mortos ou não.
	 *
	 *    @serialField allCraftsDead
	 */
	private boolean allCraftsDead = false;
	/**
	 *  Usado para armazenamento de mensagens.
	 *
	 *    @serialField map
	 */
	private TreeMap map;
	/**
	 *  Uma mensagem para ser usada no log.
	 *
	 *    @serialField mlog
	 */
	private Message mlog;
	/**
	 *  Objecto usado para manipulação da fila de espera.
	 *
	 *    @serialField object
	 */
	FifoNode object = new FifoNode();
	/**
	 *  Objecto usado para manipulação da fila de espera.
	 *
	 *    @serialField objectahead
	 */
	FifoNode objectahead = new FifoNode();

	/**
	 * Instanciação do estado geral.
	 * @param map TreeMap de armazenamento de mensagens.
	 */
	public GeneralState(TreeMap map) {
		this.map = map;
	}

	/**
	 * O cliente fica na fila de espera para comprar um produto (originada pelo cliente).
	 * @param customerId Identificação do cliente.
	 */
	public synchronized void addRequestCustomer(int customerId) {
		fifo.write(new FifoNode(customerId, 'C'));
		nOwnerReqs = nOwnerReqs + 1;
		notifyAll();
	}

	/**
	 * O artesão notifica a dona de que estão em falta matérias primas para trabalhar (originada pelo artesão).
	 * @param craftsmanId Identificação do artesão.
	 */
	public synchronized void primeMaterialsNeeded(int craftsmanId) {
		fifo.write(new FifoNode('P'));
		nOwnerReqs = nOwnerReqs + 1;
		notifyAll();

		mlog = new Message();
		mlog.setShopStat(-1, -1, '0', 'T');
		mlog.setstatCraftsman(Message.craftsmanStat.CTTE, 0, craftsmanId);
		map.put(Clock.getInstance().getValue(), mlog);
	}

	/**
	 * O artesão notifica a dona que um carregamento de produtos está pronto para ser levado (originada pelo artesão).
	 * @param craftsmanId Identificação do artesão.
	 */
	public synchronized void batchReadyForTransfer(int craftsmanId) {
		fifo.write(new FifoNode('G'));
		nOwnerReqs = nOwnerReqs + 1;
		notifyAll();

		mlog = new Message();
		mlog.setShopStat(-1, -1, 'T', '0');
		mlog.setstatCraftsman(Message.craftsmanStat.CTTE, 0, craftsmanId);
		map.put(Clock.getInstance().getValue(), mlog);
	}

	/**
	 * É adicionado um pedido vazio à fila de espera - necessário para a dona sair do "wait" em que se encontra (originada pela dona).
	 */
	public synchronized void emptyRequest() {
		fifo.write(new FifoNode('E'));
		nOwnerReqs = nOwnerReqs + 1;
		notifyAll();
	}

	/**
	 * A dona lê o pedido seguinte da fila (originado pela dona).
	 * @return A identificação na fila do pedido seguinte.
	 */
	public synchronized FifoNode readRequest() {

		if (nOwnerReqs == 0) {
			try {
				wait();
			} catch (Exception e) {
			}
		}

		object = (FifoNode) fifo.read();
		nOwnerReqs = nOwnerReqs - 1;
		if (nOwnerReqs != 0) {
			objectahead = (FifoNode) fifo.peek();
		}

		if (object.appraiseSit() == 'P' && nOwnerReqs != 0) {
			if (objectahead.appraiseSit() == 'C') {
				fifo.write(new FifoNode('P'));
				nOwnerReqs = nOwnerReqs + 1;
				notifyAll();
			}
		} else if (object.appraiseSit() == 'G' && nOwnerReqs != 0) {
			if (objectahead.appraiseSit() == 'C') {
				fifo.write(new FifoNode('G'));
				nOwnerReqs = nOwnerReqs + 1;
				notifyAll();
			}
		}

		return (object);
	}

	/**
	 * Setter da quantidade de produtos que são necessários a dona transportar da oficina para a loja (originada pelo artesão).
	 * @param nProductsTransport Quantidade de produtos que são necessários transportar.
	 */
	public void setNProductsTransport(int nProductsTransport) {
		this.nProductsTransport = nProductsTransport;
	}

	/**
	 * Getter da quantidade de produtos que são necessários a dona transportar da oficina para a loja (originada pela dona).
	 * @return Quantidade de produtos que são necessários transportar.
	 */
	public int getNProductsTransport() {
		return nProductsTransport;
	}

	/**
	 * Setter do valor do parâmetro booleano que define se todos os artesãos estão mortos ou não (originada pelo artesão).
	 * @param allCraftsDead Verificação se os artesãos estão mortos ou não.
	 */
	public void setAllCraftsDead(boolean allCraftsDead) {
		this.allCraftsDead = allCraftsDead;
	}

	/**
	 * Getter do valor do parâmetro booleano que define se todos os artesãos estão mortos ou não (originada pelo artesão).
	 * @return Verificação se os artesãos estão mortos ou não.
	 */
	public boolean isAllCraftsDead() {
		return allCraftsDead;
	}
}
